#include "AudioConvertX.h"

namespace FFMPEGCPP
{

CAudioConvert::CAudioConvert()
{
	m_pSwrContext = 0;

	m_out_ch_layout = 0;
	m_out_sample_fmt = AV_SAMPLE_FMT_NONE;
	m_out_sample_rate = 0;
	m_in_ch_layout = 0;
	m_in_sample_fmt = AV_SAMPLE_FMT_NONE;
	m_in_sample_rate = 0;

	m_pBuffer = 0;
	m_nBufferSize = 0;
	m_nDataSize = 0;
}

CAudioConvert::~CAudioConvert()
{
}

bool CAudioConvert::Init( int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate, int64_t in_ch_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate )
{

	if(m_pSwrContext)return true;

	m_pSwrContext = swr_alloc_set_opts( 0,out_ch_layout, out_sample_fmt, out_sample_rate, 
										in_ch_layout, in_sample_fmt,in_sample_rate,
										0,0);


	if( 0 == m_pSwrContext )return false;

	if( swr_init( m_pSwrContext ) )return false;

	m_out_ch_layout = out_ch_layout;
	m_out_sample_rate = out_sample_rate;
	m_out_sample_fmt = out_sample_fmt;

	m_in_ch_layout = in_ch_layout;
	m_in_sample_fmt = in_sample_fmt;
	m_in_sample_rate = in_sample_rate;
	return true;
}

void CAudioConvert::Uninit()
{

	if( m_pSwrContext )swr_free( &m_pSwrContext );
	m_pSwrContext = 0;

	m_out_ch_layout = 0;
	m_out_sample_fmt = AV_SAMPLE_FMT_NONE;
	m_out_sample_rate = 0;
	m_in_ch_layout = 0;
	m_in_sample_fmt = AV_SAMPLE_FMT_NONE;
	m_in_sample_rate = 0;

	if(m_pBuffer)av_freep(m_pBuffer);
	m_pBuffer = 0;
	m_nBufferSize = 0;
	m_nDataSize = 0;
}

bool CAudioConvert::ReInit( int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate, int64_t in_ch_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate )
{
	
	if( 
		m_out_ch_layout == out_ch_layout
		&& m_out_sample_rate == out_sample_rate
		&& m_out_sample_fmt == out_sample_fmt
		&& m_in_ch_layout == in_ch_layout
		&& m_in_sample_fmt == in_sample_fmt
		&& m_in_sample_rate == in_sample_rate )return true;


	Uninit();

	return Init(out_ch_layout, out_sample_fmt, out_sample_rate, 
				in_ch_layout, in_sample_fmt,in_sample_rate);
}

int CAudioConvert::Convert( uint8_t **out, int out_count,const uint8_t **in , int in_count )
{
	int len;
	m_nDataSize = 0;

	len = swr_convert( m_pSwrContext,out,out_count,in,in_count );
	if( len == out_count )swr_init( m_pSwrContext );

	return len;
}

int CAudioConvert::Convert( const AVFrame* pAudioFrame )
{
	int nb_samples = pAudioFrame->nb_samples;
	const uint8_t **in = (const uint8_t **)pAudioFrame->extended_data;
	uint8_t **out = (uint8_t**)&m_pBuffer;
	int		want_channels = av_get_channel_layout_nb_channels(m_out_ch_layout);
	int out_count = (int64_t)nb_samples * m_out_sample_rate / pAudioFrame->sample_rate+256;
	int out_size  = av_samples_get_buffer_size(NULL,want_channels, out_count,m_out_sample_fmt, 0);
	int	nRet;

	m_nDataSize = 0;
	av_fast_malloc( &m_pBuffer,&m_nBufferSize,out_size );

	m_nDataSize = 0;

	nRet = swr_convert( m_pSwrContext, out, out_count, in, nb_samples);
	if( nRet == out_count )swr_init( m_pSwrContext );

	if( nRet <0 )return 0;

	m_nDataSize = nRet * want_channels * av_get_bytes_per_sample(m_out_sample_fmt);

	return m_nDataSize;
}

const void* CAudioConvert::GetData()
{
	return m_pBuffer;
}

int CAudioConvert::GetDataLength()
{
	return m_nDataSize;
}

}